const path = require('path')
const inquirer = require("inquirer")
const shell = require("shelljs");
const { minidev, ConfigScope } = require('minidev')
const { logs, getPlatformInfo, openReady, compiled, WECHAT_CLI_PATH} = require("./platform-common")
const { sleep, get} = require("./common")

function isNeedLogin (e, errMsg) {
    return (e && e.scope === 'auth') || (errMsg && /授权/.test(errMsg) && /login/.test(errMsg))
}

function retryLogin () {
    return new Promise((resolve, reject) => {
        let retryCount = 0
        logs.error('登录失效', '请扫描二维码登录开发者工具')
        logs.wait('二维码准备中 ...')
        const r = () => {
            minidev.login({})
                .then(() => {
                    resolve()
                })
                .catch(async e => {
                    if (retryCount < 3) {
                        retryCount++
                        logs.error(`登录失败，进行第${retryCount}次重试...`)
                        await sleep(2000)
                        r()
                    } else {
                        reject(e)
                    }
                })
        }
        r()
    })
}

function hasLogin () {
    return new Promise((resolve, reject) => {
        const hasIsLogin = () => {
            minidev.config.get('alipay.authentication.toolId')
                .then(r => {
                    if (!r) {
                        retryLogin()
                            .then(() => {
                                hasIsLogin()
                            })
                            .catch(e => {
                                reject(e)
                            })
                    } else {
                        resolve()
                    }
                })
                .catch(e => {
                    reject(e)
                })
        }
        hasIsLogin()
    })
}

async function openIde (config, env, platform, basePath, isBuildBefore = false) {
    const platformInfo = getPlatformInfo(platform, config, basePath, env)

    await minidev.config.set('ide.appPath', platformInfo.ideDir, {
        scope: ConfigScope.GLOBAL
    })

    function openProject () {
        // 打开小程序项目
        function exec (resolve) {
            minidev.startIde({
                project: platformInfo.projectDir,
                appId: config.configData.platform.ali.appId
            })
                .then(r => {
                    resolve(r)
                })
                .catch(e => {
                    if (isNeedLogin(e, e.message)) {
                        retryLogin()
                            .finally(() => {
                                exec(resolve)
                            })
                    }
                })
        }

        return new Promise(async (resolve) => {
            logs.line()
            logs.wait('正在打开小程序开发工具 ...')
            logs.log('打开小程序项目 -> ' + platformInfo.projectDir.cyan)
            await sleep(3000)
            exec(resolve)
        })
    }

    return new Promise(resolve => {
        openReady ({
            ideDir: platformInfo.ideDir,
            projectDir: platformInfo.projectDir,
            flagFile: 'mini.project.json',
            remove: isBuildBefore
        })
            .then(res => {
                if (res === true) {
                    compiled({ config, NODE_ENV: env, UNI_PLATFORM: platform, PRESET_PATH: basePath })
                    hasLogin(platformInfo)
                        .then(() => {
                            resolve()
                            openProject()
                        })
                        .catch(e => {
                            logs.error('登录失败')
                            if (e && e.message) {
                                logs.error(e.message)
                            }
                            resolve()
                        })
                } else {
                    resolve()
                }
            })
    })
}

async function upload(config, env, type, basePath) {
    // 微信项目源码路径
    const EXEC_CODE_TYPE = env === 'development' ? 'dev' : 'build'
    const ALIPAY_PRESET_PATH = path.resolve(basePath, `./dist/${EXEC_CODE_TYPE}/${type}`)
    const VERSION = get(config, 'mp-alipay.version')
    const DESCRIPTION = get(config, 'mp-alipay.description', '') + '，cli-upload，env=' + global.NODE_ENV
    const APPID = get(config, 'configData.platform.ali.appId')

    async function _upload (resolve) {
        logs.log('上传项目', ALIPAY_PRESET_PATH.cyan)
        logs.log('AppId', APPID)
        logs.log('Version', VERSION)
        logs.log('Description', DESCRIPTION)
        logs.wait('开始上传...')
        logs.line()

        minidev.upload({
            appId: APPID,
            version: VERSION,
            deleteVersion: VERSION,
            project: ALIPAY_PRESET_PATH,
            versionDescription: DESCRIPTION
        })
            .then(res => {
                resolve(0, res)
            })
            .catch(e => {
                if (isNeedLogin(e, e.message)) {
                    retryLogin()
                        .then(() => {
                            _upload(resolve)
                        })
                        .catch(e => {
                            resolve(1, e)
                        })
                } else if (e && e.payload && e.payload.code === 'UPLOAD_MINIAPP_ERROR') {
                    if (/版本正在构建中/.test(e.payload.msg)) {
                        logs.warning('版本正在构建中，请稍后再重新尝试')
                    } else {
                        const choices = [
                            { name: `删除${VERSION}开发版本并重新上传`, value: 'delete' },
                            { name: '退出', value: 'exit' }
                        ]
                        inquirer
                            .prompt({
                                type: 'list',
                                name: 'action',
                                message: `上传代码失败，是否删除此开发版本以重新尝试上传？`,
                                choices: choices
                            })
                            .then(async answer => {
                                const action = answer.action
                                if (action === 'delete') {
                                    logs.wait('开始删除...')
                                    const r = await minidev.app.deleteVersion({
                                        appId: APPID,
                                        version: VERSION,
                                    })
                                    _upload(resolve)
                                } else if (action === 'exit') {
                                    shell.exit(1)
                                }
                            })
                    }
                } else {
                    resolve(1, e)
                }
            })
    }

    return new Promise(resolve => {
        if (VERSION) {
            _upload(resolve)
        } else {
            logs.error('未设置版本号，上传取消')
        }
    })
}

module.exports = {
    openIde,
    upload
}
